
******************************
* Part 1: compute daily prices
******************************

/*
This section uses the transactions to compute 
daily average T-ahead market prices for each instrument:
    - compute up to 40-days ahead (extendable)
    - input into performance measure: compare time t transaction price with t+T market price
    - compute (volume-)weighted and unweighted market prices
*/

clear all
set more off
cd "$FOLDER"

* Load transactions
use czech_pinter_cb_data, clear

* Prepare helpers and daily price measures
cap drop aux*
gen double aux = price * quantity

bys tradedate instrumentid: egen double u_price = mean(price)
bys tradedate instrumentid: egen double tot_q   = total(quantity)
bys tradedate instrumentid: egen double tot_qp  = total(aux)
bys tradedate instrumentid: gen  long  auxn     = _n
gen double w_price = tot_qp / tot_q

* Drop duplicate (tradedate, instrumentid), and set up daily panels
duplicates drop tradedate instrumentid, force
egen long dd = group(tradedate)

* Panel settings for forward operators
xtset instrumentid dd

* Build forward daily prices up to 40 days
forvalues i = 0/40 {
    gen double priceU_d`i' = F`i'.u_price
    gen double priceW_d`i' = F`i'.w_price
}

* Save full price-forward panel
keep priceU* priceW* instrumentid tradedate
save "CBond_price40_2020.dta", replace

* Also save t+0 slice (same-day) for transaction component usage
keep priceU_d0 priceW_d0 instrumentid tradedate
save "CBond_price40_2020_0day.dta", replace


******************************
* Part 2: merge in prices
******************************

/*
This section merges the average daily market prices (from Part 1)
with the transaction-level dataset.
*/

clear
set more off, permanently

use czech_pinter_cb_data, clear
merge m:1 instrumentid tradedate using CBond_price40_2020.dta

* Keep only matched transactions 
keep if _merge == 3
drop _merge


************************************************************
* Part 3a: duplicates to prepare for performance computations
************************************************************

/*
Duplicate each transaction so we can compute performance/volume/transaction number
from the point of view of both:
    (i)  the reporting firm, and
    (ii) the counterparty.
Define buy/sell dummy ("bs_clients") accordingly.
*/

expand 2, gen(flagDUP)

* Investor identifier (call) and type (callTy)
cap drop call
gen long call = reportingfirmid   if flagDUP == 0
replace  call = counterpartyoneid if flagDUP == 1

cap drop callTy
gen long callTy = reportingfirmtype   if flagDUP == 0
replace  callTy = counterpartyonetype if flagDUP == 1

* Buy-sell indicator from client perspective
cap drop bs_clients
gen int bs_clients = buysellnumeric       if flagDUP == 0
replace   bs_clients = buysellnumeric * -1 if flagDUP == 1

* Counterparty (coun) ID and type (counTy)
cap drop coun
gen long coun = reportingfirmid   if flagDUP == 1
replace  coun = counterpartyoneid if flagDUP == 0

cap drop counTy
gen long counTy = reportingfirmtype   if flagDUP == 1
replace  counTy = counterpartyonetype if flagDUP == 0


 ***************************************************************************
 * Part 3b: clients 
 ***************************************************************************

* Drop certain client categories (keep investors; drop dealer banks)
drop if callTy == 12   /* Dealers as clients */

**********************
* Client–day connections (two definitions)
**********************
cap drop aux* day_*
bys call tradedate: egen long day_OR1_ful = nvals(coun)
bys call tradedate: egen long aux = nvals(coun) if counTy == 12   /* 12 = dealer */
bys call tradedate: egen long day_OR1_bip = min(aux)

bys call tradedate: gen long aux2 = _n

* Client–day–instrument connections (two definitions)
cap drop aux*
bys call tradedate instrumentid: egen long day_INS_ful = nvals(coun)
bys call tradedate instrumentid: egen long aux = nvals(coun) if counTy == 12
bys call tradedate instrumentid: egen long day_INS_bip = min(aux)

bys call tradedate instrumentid: gen long aux2 = _n

* Final save
save Perf2020jan.dta, replace




******************************************************************
* Part 4: performance computations
******************************************************************

/*
Compute performance for each client:
  - focus on clients (Dealer-Banks already handled in earlier parts)

Connections (pre-computed in Part 3):
  (i) "day_OR1_bip": trades with dealers (binary presence)
  (ii) "day_OR1_ful": trades with any other agents (binary presence)
*/

*--------------------------------------------------------------
* Merge in 0-day market price slice (for reference; forward prices already present)
*--------------------------------------------------------------
merge m:1 tradedate instrumentid using CBond_price40_2020_0day.dta
keep if _merge == 3
drop _merge

*----------------------------------------------------------------------------------------------------------------------------
* Signed %-return per transaction up to 40-day horizon (to remove execution component, replace price with 0-day average price)
*----------------------------------------------------------------------------------------------------------------------------
capture drop dim*
forvalues i = 0/40 {
    quietly gen double dimProfitUnw_`i' = (ln(priceU_d`i') - ln(price)) * bs_clients
}

* Month tags
gen int  dyear  = year(tradedate)
gen byte dmonth = month(tradedate)
egen long mm    = group(dyear dmonth)

* Drop self-trades
drop if call == coun

******************************************************************
* Client-day-instrument level performance (1) against all counterparties
******************************************************************
preserve

    * Aggregates per client-day-instrument
    bys call tradedate instrumentid: egen double clientQuantityDaily = total(quantity)

    * Average daily transaction count proxy
    capture drop transactionDaily*
    capture drop aux*
    gen long auxn = _n
    bys call tradedate instrumentid: egen long transactionDaily = nvals(auxn)

    * Winsorize transaction-level %-returns at 1–99% 
    forvalues i = 0/40 {
        quietly {
            egen double p1_`i'  = pctile(dimProfitUnw_`i'), p(1)
            egen double p99_`i' = pctile(dimProfitUnw_`i'), p(99)
            replace dimProfitUnw_`i' = p99_`i' if dimProfitUnw_`i' > p99_`i' & dimProfitUnw_`i' < .
            replace dimProfitUnw_`i' = p1_`i'  if dimProfitUnw_`i' < p1_`i'
            drop p1_`i' p99_`i'
        }
    }

    * Quantity-weight computations
    forvalues i = 0/40 {
        gen double dimProfit_`i' = dimProfitUnw_`i' * quantity
    }

    * Weighted and Unweighted performance
    forvalues i = 0/40 {
        capture drop aux*
        bys call tradedate instrumentid: egen double aux = total(dimProfit_`i')
        gen double dimTS`i'ClientWeighted = aux / clientQuantityDaily
        bys call tradedate instrumentid: egen double dimTS`i'ClientUnw = mean(dimProfitUnw_`i')
    }

    * De-duplicate to client-day-instrument
    duplicates drop call tradedate instrumentid, force

    * Save (all counterparties)
    save aggregate_INS_all.dta, replace

restore



******************************************************************
* Client-day level performance (1) against all counterparties
******************************************************************

preserve

*-----------------------------------------------------------*
* Aggregate daily client-level stats
*-----------------------------------------------------------*
bys call tradedate: egen clientQuantityDaily = total(quantity)

******************************************************************
* Average daily number of transactions
******************************************************************
cap drop transactionDaily* aux*
gen auxn = _n
bys call tradedate: egen transactionDaily = nvals(auxn)

*-----------------------------------------------------------*
* Winsorise transaction-level %-returns at 1-99% level
*-----------------------------------------------------------*
forvalues i = 0/40 {
    di `i'
    qui {
        capture confirm variable dimProfitUnw_`i'
        if !_rc {
            quietly _pctile dimProfitUnw_`i', p(1 99)
            scalar p1 = r(r1)
            scalar p99 = r(r2)
            replace dimProfitUnw_`i' = p99 if dimProfitUnw_`i' > p99 & dimProfitUnw_`i' < .
            replace dimProfitUnw_`i' = p1  if dimProfitUnw_`i' < p1
        }
    }
}

*-----------------------------------------------------------*
* Compute quantity*price for weighted performance
*-----------------------------------------------------------*
forvalues i = 0/40 {
    capture confirm variable dimProfitUnw_`i'
    if !_rc {
        gen dimProfit_`i' = dimProfitUnw_`i' * quantity
    }
}

*-----------------------------------------------------------*
* Weighted and Unweighted Performance Measures
*-----------------------------------------------------------*
forvalues i = 0/40 {
    di `i'
    * 1. Weighted by turnover
    cap drop aux*
    bys call tradedate: egen aux = total(dimProfit_`i')
    gen dimTS`i'ClientWeighted = aux / clientQuantityDaily

    * 2. Unweighted by volume
    bys call tradedate: egen dimTS`i'ClientUnw = mean(dimProfitUnw_`i')
}

*-----------------------------------------------------------*
* Final clean-up and save
*-----------------------------------------------------------*
duplicates drop call tradedate, force
xtset call tradedate

save aggregate_day_all, replace   

restore
